#include "app_modbus.h"

static modbus_t *modbus_ctx = NULL;
// {"device_id":1,"motor_set_nums":800,"motor_status":"on"}
/**
 * @brief modbus 初始化 
 *     //1 初始化 modbus 上下文
    //2 设置调试方式
    //3 设置控制收发的方式
    //4 设置超时时间 
    //5 连接
 */
int app_modbus_init(char *dev_file_name)
{
    //1 初始化 modbus 上下文
    modbus_ctx = modbus_new_rtu(dev_file_name, 115200, 'N', 8, 1);
    if (modbus_ctx == NULL)
    {
        perror("modbus_new_rtu() failed\n");
        return -1;
    }

    //2 设置调试方式
    modbus_set_debug(modbus_ctx, TRUE);
    //3 设置控制收发的方式 自动控制
    modbus_rtu_set_rts(modbus_ctx, MODBUS_RTU_RTS_NONE);
    //4 设置超时时间 
     modbus_set_response_timeout(modbus_ctx, 1, 0);
    //5 连接
    if(modbus_connect(modbus_ctx) == -1)
    {
        modbus_free(modbus_ctx);
        perror("modbus_connect() failed\n");
        return -1;
    }
    log_info("modbus_connect() ok\n");
    return 0;

}


/**
 * @brief 线圈读   电机当前的开关状态
 * 1 flush ctx 
 * 2 设置 slave_id
 * 3 执行指令  如果失败  flush ctx 重新执行
 */
int app_modbus_readCoil(int slave_id, int start_address,  uint16_t reg_nums, uint8_t *buff)
{
    usleep(5000);
//    * 1 flush ctx 
    modbus_flush(modbus_ctx);
//  * 2 设置 slave_id
    modbus_set_slave(modbus_ctx, slave_id);
//  * 3 执行指令  如果失败  flush ctx 重新执行
    int ret = modbus_read_bits(modbus_ctx, start_address, reg_nums, buff);
    if(ret < 0)
    {   
        log_info("modbus_read_bits retry ...");
        usleep(5000);
        modbus_flush(modbus_ctx);
        ret = modbus_read_bits(modbus_ctx, start_address, reg_nums, buff);
        if(ret < 0)
        {
            log_error("modbus_read_bits error %s", modbus_strerror(errno));
            return -1;
        }
    }
    log_info("modbus_read_bits success  " );
    return 0;
}

/**
 * @brief 线圈写   操作电机的开关
 */
int app_modbus_writeCoil(int slave_id, int start_address,  uint16_t reg_nums, uint8_t *data)
{
    usleep(5000);
    // * 1 flush ctx 
    modbus_flush(modbus_ctx);
//  * 2 设置 slave_id
    modbus_set_slave(modbus_ctx, slave_id);
//  * 3 执行指令  如果失败  flush ctx 重新执行
    int ret = modbus_write_bits(modbus_ctx, start_address, reg_nums, data);
    if(ret < 0)
    {   
        log_info("modbus_write_bits retry ...");
        usleep(5000);
        modbus_flush(modbus_ctx);
        ret = modbus_write_bits(modbus_ctx, start_address, reg_nums, data);
        if(ret < 0)
        {
            log_error("modbus_write_bits error %s", modbus_strerror(errno));
            return -1;
        }
    }
    log_info("modbus_write_bits success  " );
    return 0;
}


/**
 * @brief 保持寄存器写   设置转速
 */
int app_modbus_writeHoldingRegister(int slave_id, int start_address,  uint16_t reg_nums, uint16_t *data)
{
    usleep(5000);
    //    * 1 flush ctx 
    modbus_flush(modbus_ctx);
//  * 2 设置 slave_id
    modbus_set_slave(modbus_ctx, slave_id);
//  * 3 执行指令  如果失败  flush ctx 重新执行
    int ret = modbus_write_registers(modbus_ctx, start_address, reg_nums, data);
    if(ret < 0)
    {   
        log_info("modbus_write_registers retry ...");
        usleep(5000);
        modbus_flush(modbus_ctx);
        ret = modbus_write_registers(modbus_ctx, start_address, reg_nums, data);
        if(ret < 0)
        {
            log_error("modbus_write_registers error %s", modbus_strerror(errno));
            return -1;
        }
    }
    log_info("modbus_write_registers success  " );
    return 0;


}

/**
 * @brief 读取输入寄存器  获取当前转速
 */
int app_modbus_readInputRegister(int slave_id, int start_address,  uint16_t reg_nums, uint16_t *buff)
{
    usleep(5000);
        //    * 1 flush ctx 
    modbus_flush(modbus_ctx);
//  * 2 设置 slave_id
    modbus_set_slave(modbus_ctx, slave_id);
//  * 3 执行指令  如果失败  flush ctx 重新执行
    int ret = modbus_read_input_registers(modbus_ctx, start_address, reg_nums, buff);
    if(ret < 0)
    {   
        log_info("modbus_read_input_registers retry ...");
        usleep(5000);
        modbus_flush(modbus_ctx);
        ret = modbus_read_input_registers(modbus_ctx, start_address, reg_nums, buff);
        if(ret < 0)
        {
            log_error("modbus_read_input_registers error %s", modbus_strerror(errno));
            return -1;
        }
    }
    log_info("modbus_read_input_registers success  " );
    return 0;
}


/**
 * @brief 销毁modbus
 */
void app_modbus_destroy(void)
{
    if(modbus_ctx)
    {
        modbus_close(modbus_ctx);
        modbus_free(modbus_ctx);
    }
}